home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 424_01 / ed_157 / load_file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-24  |  58.1 KB  |  2,166 lines

  1. /*
  2.  * Copyright (C) 1992 by Rush Record
  3.  * Copyright (C) 1993 by Charles Sandmann (sandmann@clio.rice.edu)
  4.  * 
  5.  * This file is part of ED.
  6.  * 
  7.  * ED is free software; you can redistribute it and/or modify it under the terms
  8.  * of the GNU General Public License as published by the Free Software Foundation.
  9.  * 
  10.  * ED is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  11.  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  12.  * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
  13.  * 
  14.  * You should have received a copy of the GNU General Public License along with ED
  15.  * (see the file COPYING).  If not, write to the Free Software Foundation, 675
  16.  * Mass Ave, Cambridge, MA 02139, USA.
  17.  */
  18. #include "opsys.h"
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <time.h>
  25.  
  26. #ifndef NO_MMAP
  27. #include <sys/types.h>
  28. #include <sys/mman.h>
  29. #endif
  30.  
  31. #include "unistd.h"
  32. #include "memory.h"
  33. #include "file.h"
  34. #include "ctyp_dec.h"
  35.  
  36. #define FILENAME_OFFSET 40    /* this is the offset from the beginning of diredit records to the file name */
  37.  
  38. #ifndef O_BINARY
  39. #define O_BINARY 0
  40. #endif
  41.  
  42. /* NOTE: BLOCK_SIZE cannot be larger than BUFFER_SIZE */
  43. #define BLOCK_SIZE 512
  44. /* NOTE: BLOCK_SIZE must be an even multiple of BINARY_RECSIZE */
  45. #define BUFFER_SIZE 2048
  46.  
  47. #include "rec.h"
  48. #include "window.h"
  49. #include "ed_dec.h"
  50.  
  51. typedef struct mmap_str *mmap_ptr;
  52. typedef struct mmap_str
  53. {
  54.     mmap_ptr next;
  55.     Char *adr;
  56.     Int len;
  57. } mmap_node;
  58.  
  59. static mmap_ptr base = NULL;
  60. static Char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  61. static Char ftpbin = 0;    /* flags a binary ftp'ed file was just loaded */
  62. static Char foundusr[128];
  63. static Char foundpwd[128];
  64. static Char fileonly = 0;    /* flag to prevent interpretation of fname as dirname */
  65. static Char forcebinary = 0;    /* flag to force binary transfer of file */
  66. static Char maperror = 0;    /* flag that a map_file error other than ENOENT has occurred */
  67.  
  68. extern Char *extension();
  69. extern Char *filename();
  70. extern Char *ftp_cwd();
  71. extern Char *last_message();
  72. #ifndef VMS
  73. extern char *sys_errlist[];
  74. #endif
  75.  
  76. /******************************************************************************\
  77. |Routine: filename_offset
  78. |Callby: command edit
  79. |Purpose: Returns the offset to the file name in diredit records.
  80. |Arguments:
  81. |    none
  82. \******************************************************************************/
  83. Int filename_offset()
  84. {
  85.     return(FILENAME_OFFSET);
  86. }
  87.  
  88. /******************************************************************************\
  89. |Routine: mode_string
  90. |Callby: read_in_diredit
  91. |Purpose: Returns a string expressing the file's permissions, as in: rwxr-xr-x.
  92. |Arguments:
  93. |    mode is the file mode.
  94. \******************************************************************************/
  95. Char *mode_string(mode)
  96. Int mode;
  97. {
  98.     static char rbuf[10];
  99.     
  100.     memset(rbuf,'-',9);
  101.     rbuf[9] = '\0';
  102.     if(mode & 1)
  103.         rbuf[8] = 'x';
  104.     if(mode & 2)
  105.         rbuf[7] = 'w';
  106.     if(mode & 4)
  107.         rbuf[6] = 'r';
  108.     if(mode & 8)
  109.         rbuf[5] = 'x';
  110.     if(mode & 16)
  111.         rbuf[4] = 'w';
  112.     if(mode & 32)
  113.         rbuf[3] = 'r';
  114.     if(mode & 64)
  115.         rbuf[2] = 'x';
  116.     if(mode & 128)
  117.         rbuf[1] = 'w';
  118.     if(mode & 256)
  119.         rbuf[0] = 'r';
  120.     return(rbuf);
  121. }
  122.  
  123. /******************************************************************************\
  124. |Routine: size_string
  125. |Callby: read_in_diredit
  126. |Purpose: Returns a string expressing the file size in 6 bytes.
  127. |Arguments:
  128. |    size is the size of the file in bytes.
  129. \******************************************************************************/
  130. Char *size_string(size)
  131. Int size;
  132. {
  133.     static char rbuf[9];
  134.     
  135.     if(size > 99999999)
  136.         sprintf(rbuf,"%5dmeg",size / 1000000);
  137.     else
  138.         sprintf(rbuf,"%8d",size);
  139.     return(rbuf);
  140. }
  141.  
  142. /******************************************************************************\
  143. |Routine: parse_vms_perms
  144. |Callby: parse_vms_mode read_in_diredit
  145. |Purpose: Parses expressions like RWED. Returns unix-style mode.
  146. |Arguments:
  147. |    p is a pointer in the string that presumably contains the permissions. This
  148. |      string may be empty, in which case it is terminated by , or \0 or ).
  149. |    mode is the returned mode, as in rwx.
  150. \******************************************************************************/
  151. void parse_vms_perms(p,mode)
  152. Char *p,*mode;
  153. {
  154.     memset(mode,'-',3);
  155.     while(1)
  156.         switch(*p++)
  157.         {
  158.             case 'R':
  159.                 mode[0] = 'r';
  160.                 break;
  161.             case 'W':
  162.                 mode[1] = 'w';
  163.                 break;
  164.             case 'E':
  165.                 mode[2] = 'x';
  166.                 break;
  167.             case 'D':
  168.                 break;
  169.             default:
  170.                 return;
  171.         }
  172. }
  173.  
  174. /******************************************************************************\
  175. |Routine: parse_vms_mode
  176. |Callby: read_in_diredit
  177. |Purpose: Parses expressions like (RWED,RE,RE,). Returns unix-style mode.
  178. |Arguments:
  179. |    p is a pointer in the string that presumably contains the permissions.
  180. |    mode is the returned mode, as in rwxr-xr-w.
  181. \******************************************************************************/
  182. void parse_vms_mode(p,mode)
  183. Char *p,*mode;
  184. {
  185.     Char *q;
  186.     
  187.     mode[9] = '\0';
  188.     if((q = strchr(p,'(')))
  189.     {
  190.         if((p = strchr(q,',')))
  191.         {
  192.             parse_vms_perms(++p,mode);
  193.             if((q = strchr(p,',')))
  194.             {
  195.                 parse_vms_perms(++q,mode + 3);
  196.                 if((p = strchr(q,',')))
  197.                     parse_vms_perms(++p,mode + 6);
  198.                 else
  199.                     goto badmode;
  200.             }
  201.             else
  202.                 goto badmode;
  203.         }
  204.         else
  205.             goto badmode;
  206.         return;
  207.     }
  208. badmode:
  209.     strcpy(mode,"?????????");
  210. }
  211.  
  212. /******************************************************************************\
  213. |Routine: fix_vms_dir
  214. |Callby: read_in_diredit
  215. |Purpose: Converts *.dir;1 or *.DIR;1 to [.dir] or [.DIR]. Also strips device
  216. |         and directory from the name, and packages it in [].
  217. |Arguments:
  218. |    file is the input file name.
  219. |    ret is the returned file name (same as file if .dir not present).
  220. \******************************************************************************/
  221. void fix_vms_dir(file,ret)
  222. Char *file,*ret;
  223. {
  224.     Char buf[512],*p,*q;
  225.     
  226.     strcpy(buf,file);
  227.     q = buf;
  228.     if((p = strstr(buf,".DIR;1")))
  229.     {
  230.         *p = '\0';
  231.         while(q != p && *p != ']' && *p != '>')
  232.             p--;
  233.         if(q != p)
  234.             p++;
  235.         sprintf(ret,"[.%s]",p);
  236.     }
  237.     else if((p = strstr(buf,".dir;1")))    /* oddball lowercase VMS system */
  238.     {
  239.         *p = '\0';
  240.         while(q != p && *p != ']' && *p != '>')
  241.             p--;
  242.         if(q != p)
  243.             p++;
  244.         sprintf(ret,"[.%s]",++p);
  245.     }
  246.     else    /* just strip device/directory */
  247.     {
  248.         for(p = buf,q = buf + strlen(buf) - 1;p != q && *q != ']' && *q != '>';)
  249.             q--;
  250.         if(q != p)
  251.             q++;
  252.         strcpy(ret,q);
  253.     }
  254. }
  255.  
  256. /******************************************************************************\
  257. |Routine: fake_date
  258. |Callby: read_in_diredit
  259. |Purpose: Makes up a fake set of information about a file when parsing fails.
  260. |Arguments:
  261. |    none
  262. \******************************************************************************/
  263. void fake_date(size,year,month,day,hour,minute)
  264. Int *size,*year;
  265. Char *month;
  266. Int *day,*hour,*minute;
  267. {
  268.     *size = 0;
  269.     *year = 1955;
  270.     strcpy(month,"Feb");
  271.     *day = 8;
  272.     *hour = 6;
  273.     *minute = 35;
  274. }
  275.  
  276. /******************************************************************************\
  277. |Routine: parse_monthyear
  278. |Callby: read_in_diredit
  279. |Purpose: Deals with month and year in VMS listings.
  280. |Arguments:
  281. |    monthyear is the string that combines the month and year.
  282. |    size is the (possibly) returned file size in bytes.
  283. |    year is the (possibly) returned year.
  284. |    month is the returned month.
  285. |    day is the (possibly) returned day.
  286. |    ihour is the (possibly) returned hour.
  287. |    minute is the (possibly) returned minute.
  288. |    mode is the returned file mode.
  289. |    p is a pointer to the listing record.
  290. \******************************************************************************/
  291. void parse_monthyear(monthyear,size,year,month,day,ihour,minute,mode,p)
  292. Char *monthyear;
  293. Int *size,*year;
  294. Char *month;
  295. Int *day,*ihour,*minute;
  296. Char *mode;
  297. Char *p;
  298. {
  299.     Char *q;
  300.     
  301.     if((q = strchr(monthyear,'-')))
  302.     {
  303.         *q++ = '\0';
  304.         strcpy(month,monthyear);
  305.         if(my_sscanf(q,"%d",year) == 1)
  306.         {
  307.             parse_vms_mode(p,mode);
  308.             return;
  309.         }
  310.     }
  311.     fake_date(size,year,month,day,ihour,minute);    /* use fake date info */
  312. }
  313.  
  314. /******************************************************************************\
  315. |Routine: force_binary
  316. |Callby: edit
  317. |Purpose: Flags that the next file opened will be in binary mode.
  318. |Arguments:
  319. |    none
  320. \******************************************************************************/
  321. void force_binary()
  322. {
  323.     forcebinary = 1;
  324. }
  325.  
  326. /******************************************************************************\
  327. |Routine: ftp_fileonly
  328. |Callby: edit
  329. |Purpose: Flags that the next file opened will skip the directory check.
  330. |Arguments:
  331. |    none
  332. \******************************************************************************/
  333. void ftp_fileonly()
  334. {
  335.     fileonly = 1;
  336. }
  337.  
  338. /******************************************************************************\
  339. |Routine: netrc_password
  340. |Callby: ftp_open
  341. |Purpose: Returns netrc password or NULL string.
  342. |Arguments:
  343. |    none
  344. \******************************************************************************/
  345. Char *netrc_password()
  346. {
  347.     return(foundpwd);
  348. }
  349.  
  350. /******************************************************************************\
  351. |Routine: netrc_token
  352. |Callby: find_netrc
  353. |Purpose: Gets a token from the .netrc file.
  354. |Arguments:
  355. |    fp is the file pointer of the .netrc file.
  356. \******************************************************************************/
  357. Char *netrc_token(fp)
  358. FILE *fp;
  359. {
  360.     static Char tok[512],*p;
  361.     Int c;
  362.     
  363.     while(1)
  364.     {
  365.         if((c = fgetc(fp)) < 0)
  366.         {
  367.             fclose(fp);
  368.             return(NULL);
  369.         }
  370.         if(isspace(c))
  371.             continue;
  372.         p = tok;
  373.         *p++ = c;
  374.         while(1)
  375.         {
  376.             if((c = fgetc(fp)) < 0)
  377.             {
  378.                 *p++ = '\0';
  379.                 return(tok);
  380.             }
  381.             if(isspace(c))
  382.             {
  383.                 *p++ = '\0';
  384.                 return(tok);
  385.             }
  386.             *p++ = c;
  387.         }
  388.     }
  389. }
  390.  
  391. /******************************************************************************\
  392. |Routine: find_netrc
  393. |Callby: extract_host
  394. |Purpose: Looks up a host in the user's netrc file. Returns pointer to username,
  395. |         or NULL if no matching host is found.
  396. |Arguments:
  397. |    host is the host we're looking for.
  398. \******************************************************************************/
  399. Char *find_netrc(host)
  400. Char *host;
  401. {
  402.     FILE *fp;
  403.     Char *p,file[512];
  404.     struct stat statbuf;
  405.     
  406.     foundpwd[0] = '\0';    /* we check for netrc password when opening connection */
  407. #ifdef VMS
  408.     strcpy(file,"SYS$LOGIN:.NETRC;");
  409. #else
  410.     strcpy(file,"$HOME/.netrc");
  411. #endif
  412.     envir_subs(file);
  413.     if(!stat(file,&statbuf))
  414.     {
  415.         if((statbuf.st_mode & 0x1ff) == 0x180)    /* require rw------- permission */
  416.         {
  417.             if((fp = fopen(file,"r")))    /* open the .netrc file */
  418.             {
  419.                 while((p = netrc_token(fp)))    /* get tokens */
  420.                 {
  421.                     if(!inscmp(p,"machine"))
  422.                     {
  423.                         if(!(p = netrc_token(fp)))    /* get machine name */
  424.                             return(NULL);
  425.                         if(!inscmp(host,p))    /* a hit on the machine name */
  426.                         {
  427.                             while((p = netrc_token(fp)))
  428.                             {
  429.                                 if(!inscmp(p,"password"))
  430.                                 {
  431.                                     if(!(p = netrc_token(fp)))
  432.                                         return(NULL);
  433.                                     fclose(fp);
  434.                                     strcpy(foundpwd,p);
  435.                                     return(foundusr);
  436.                                 }
  437.                                 else if(!inscmp(p,"login"))
  438.                                 {
  439.                                     if(!(p = netrc_token(fp)))
  440.                                         return(NULL);
  441.                                     strcpy(foundusr,p);
  442.                                 }
  443.                                 else if(!inscmp(p,"machine"))
  444.                                 {
  445.                                     fclose(fp);
  446.                                     return(foundusr);    /* user but no password, prompt them later */
  447.                                 }
  448.                             }
  449.                             return(foundusr);    /* user but no password, prompt them later */
  450.                         }
  451.                     }
  452.                 }
  453.             }
  454.         }
  455.     }
  456.     return(NULL);
  457. }
  458.  
  459. /******************************************************************************\
  460. |Routine: was_binary
  461. |Callby: load_file
  462. |Purpose: Tells caller whether the last file loaded was loaded in BINARY mode.
  463. |Arguments:
  464. |    none
  465. \******************************************************************************/
  466. Int was_binary()
  467. {
  468.     if(ftpbin)
  469.     {
  470.         ftpbin = 0;
  471.         return(1);
  472.     }
  473.     return(0);
  474. }
  475.  
  476. /******************************************************************************\
  477. |Routine: extract_host
  478. |Callby: output_file read_in_diredit
  479. |Purpose: Extracts host and user names from file spec, and pointer to path.
  480. |Arguments:
  481. |    i is the offset in lbuf of the path name.
  482. |    lbuf is the complete file name.
  483. |    host is the returned host name.
  484. |    usr is the returned user name.
  485. \******************************************************************************/
  486. Char *extract_host(i,lbuf,host,usr)
  487. Int i;
  488. Char *lbuf,*host,*usr;
  489. {
  490.     Int l;
  491.     Char *p,*q,*r;
  492.     
  493.     p = lbuf + i;    /* points to directory name */
  494.     memcpy(host,lbuf + 1,(l = p - lbuf - 2));
  495.     host[l] = '\0';
  496.     if((q = strchr(host,'@')))
  497.     {
  498.         foundpwd[0] = '\0';    /* prevent old password from being used for new user/host */
  499.         memcpy(usr,host,(l = q - host));
  500.         usr[l] = '\0';
  501.         for(q++,r = host;(*r++ = *q++););    /* eliminate the username from the host string */
  502.     }
  503.     else    /* no user specified, check .netrc */
  504.     {
  505.         if((q = find_netrc(host)))
  506.             strcpy(usr,q);
  507.         else
  508.             strcpy(usr,"anonymous");    /* no .netrc, use "anonymous" */
  509.     }
  510.     return(p);
  511. }
  512.  
  513. #ifndef NO_FTP
  514. /******************************************************************************\
  515. |Routine: host_filename
  516. |Callby: output_file read_in_diredit
  517. |Purpose: Parses filenames depending on host type.
  518. |Arguments:
  519. |    i is the offset in lbuf of the path name.
  520. |    lbuf is the complete file name.
  521. |    fname is the returned, processed file name.
  522. \******************************************************************************/
  523. Char *host_filename(i,lbuf,fname)
  524. Int i;
  525. Char *lbuf,*fname;
  526. {
  527.     Int ftpsystem;
  528.     Char *p,*q,*r,buf[512];
  529.     
  530.     ftpsystem = ftp_system(lbuf);
  531.     p = lbuf + i;    /* points to directory name */
  532.     if(ftp_unixy(ftpsystem))    /* if server system is unix or dos or os/2 or wnt... */
  533.     {
  534.         if(!*p)
  535.             strcpy(p,".");    /* turn /xxx.yyy.zzz: into /xxx.yyy.zzz:/ */
  536.         while((q = strstr(lbuf + i,"/../")))    /* handle '..' present in file name */
  537.         {
  538.             for(r = q - 1;r > lbuf && *r != '/' && *r != ':';r--);
  539.             if(*r == ':')    /* they tried to back up from top level */
  540.             {
  541.                 *++r = '/';
  542.                 *++r = '\0';
  543.             }
  544.             else if(r != lbuf && *r == '/')    /* eat everything from preceeding / to last . in /../ */
  545.                 for(q += 3;(*r++ = *q++););
  546.         }
  547.         if(p[strlen(p) - 1] != '/')    /* be sure dirname ends with '/' */
  548.             strcat(p,"/");
  549.         if(!strncmp(p,"./",2))
  550.         {
  551.             sprintf(buf,"%s/%s",ftp_cwd(),p + 2);
  552.             sprintf(p,"%s",buf);
  553.             while((q = strstr(lbuf,"//")))
  554.                 for(r = q + 1;(*q++ = *r++););
  555.         }
  556.     }
  557.     else    /* server is VMS or VM */
  558.     {
  559.         if(!*p)    /* nothing present past /host: */
  560.             strcpy(p,ftp_cwd());
  561.         else if(!strchr(p,'['))
  562.         {
  563.             strcpy(buf,ftp_cwd());
  564.             strcat(buf,p);
  565.             strcpy(p,buf);
  566.         }
  567.         if(p[strlen(p) - 1] == '/')    /* strip trailing '/' from dirname */
  568.             p[strlen(p) - 1] = '\0';
  569.         while((q = strstr(p,"][.")))    /* collapse things like [a][.b] to [a.b] */
  570.             while((*q = *(q + 2)))
  571.                 q++;
  572.         if((q = strstr(p,"[-]")))    /* move up in directory hierarchy if indicated */
  573.         {
  574.             if(ftpsystem == 'I' || ftpsystem == 'T')    /* VM and MTS systems don't have 'up' */
  575.                 *q = '\0';
  576.             else
  577.             {
  578.                 while(q > p)
  579.                 {
  580.                     if(*--q == '.')
  581.                     {
  582.                         strcpy(q,"]");
  583.                         break;
  584.                     }
  585.                     if(*q == ':')    /* they tried to move up from top level */
  586.                     {
  587.                         strcpy(q,ftp_cwd());
  588.                         break;
  589.                     }
  590.                 }
  591.                 if(q == p)
  592.                     strcpy(p,ftp_cwd());
  593.             }
  594.         }
  595.         else if(!strncmp(p,"[]",2))
  596.         {
  597.             sprintf(buf,"%s%s",ftp_cwd(),p + 2);
  598.             sprintf(p,"%s",buf);
  599.         }
  600.         else if(!strncmp(p,"[.",2))
  601.         {
  602.             strcpy(buf,ftp_cwd());
  603.             strcat(buf,p);
  604.             strcpy(p,buf);
  605.             while((q = strstr(p,"][.")))    /* collapse things like [a][.b] to [a.b] */
  606.                 while((*q = *(q + 2)))
  607.                     q++;
  608.         }
  609.     }
  610.     strcpy(fname,lbuf);    /* return the actual name */
  611.     return(p);
  612. }
  613.  
  614. /******************************************************************************\
  615. |Routine: ftp_date
  616. |Callby: load_file
  617. |Purpose: Converts a directory listing date/time entry into yyyy mm-dd hh:mm.
  618. |Arguments:
  619. |    month is the month, one of Jan, Feb,...
  620. |    day is the day of the month.
  621. |    hour is hh:mm or yyyy.
  622. \******************************************************************************/
  623. Char *ftp_date(month,day,hour)
  624. Char *month,*hour;
  625. Int day;
  626. {
  627.     Char *buf;
  628.     static Char buf2[128];
  629.     time_t l;
  630.  
  631. /* get the year */
  632.     if(hour[2] == ':')
  633.     {
  634.         l = time(0);
  635.         buf = (Char *)ctime(&l);
  636.         memcpy(buf2,buf + 20,4);
  637.     }
  638.     else
  639.         memcpy(buf2,hour,4);
  640.     buf2[4] = ' ';
  641. /* do the month */
  642.     sprintf(buf2 + 5,"%02d-",(int)((strstr(months,month) - months) / 3) + 1);
  643. /* do the day */
  644.     sprintf(buf2 + 8,"%02d",day);
  645.     buf2[10] = ' ';
  646. /* do hours, minutes */
  647.     if(hour[2] != ':')
  648.         strcpy(buf2 + 11,"00:00");
  649.     else
  650.         memcpy(buf2 + 11,hour,5);
  651.     buf2[16] = '\0';
  652.     return(buf2);
  653. }
  654. #endif
  655.  
  656. /******************************************************************************\
  657. |Routine: proper_date
  658. |Callby: read_in_diredit
  659. |Purpose: Converts a statbuf mtime entry into yyyy mm-dd hh:mm.
  660. |Arguments:
  661. |    mtime is the statbuf mtime entry.
  662. \******************************************************************************/
  663. Char *proper_date(mtime)
  664. time_t mtime;
  665. {
  666.     Char *buf,monbuf[4];
  667.     static Char buf2[64];
  668.  
  669.     buf = ctime(&mtime);
  670.     if(!buf)
  671.     {
  672.         strcpy(buf2,"1960 04-18 02:35");    /* CWS if mtime bogus */
  673.         return(buf2);
  674.     }
  675.     memcpy(buf2,buf + 20,4);
  676.     buf2[4] = ' ';
  677.     memcpy(monbuf,buf + 4,3);
  678.     monbuf[3] = '\0';
  679.     sprintf(buf2 + 5,"%02d-",(int)((strstr(months,monbuf) - months) / 3) + 1);
  680.     memcpy(buf2 + 8,buf + 8,8);
  681.     if(buf2[8] == ' ')
  682.         buf2[8] = '0';
  683.     buf2[16] = '\0';
  684.     return(buf2);
  685. }
  686.  
  687. /******************************************************************************\
  688. |Routine: map_file
  689. |Callby: load_file
  690. |Purpose: Maps a file into memory.
  691. |Arguments:
  692. |    file is the name of the file.
  693. |    bytes is the returned size of the mapped area in bytes.
  694. \******************************************************************************/
  695. Char *map_file(file,bytes)
  696. Char *file;
  697. Int *bytes;
  698. {
  699.     struct stat statbuf;
  700.     Int fd;
  701.     Char *p,*errmsg,buf[512];
  702.     mmap_ptr m;
  703. #ifdef VMS
  704.     Char *q;
  705.     Int remain,nbytes;
  706. #endif
  707. #ifdef NO_MMAP
  708.     Int l;
  709. #endif
  710.     
  711. /* get the file's size in bytes */
  712.     if(stat(file,&statbuf) < 0)
  713.     {
  714. #ifdef VMS
  715.         return(0);    /* VMS doesn't really support errno, nor even vaxc$errno */
  716. #else
  717. report_error:
  718.         if(errno == ENOENT)
  719.             return(0);
  720.         sprintf(buf,"Unable to open file '%s'.",file);
  721.         slip_message(buf);
  722.         errmsg = (Char *)sys_errlist[errno];
  723.         slip_message(errmsg);
  724.         wait_message();
  725.         maperror = 1;
  726.         return(0);
  727. #endif
  728.     }
  729.         
  730. /* open the file */
  731. #ifdef VMS
  732.     if((fd = open(file,O_RDONLY,0,"ctx=rec","rfm=fix","mrs=512","shr=get,put,del,mse,upi,upd")) < 0)
  733.         return(0);
  734. #else
  735.     if((fd = open(file,O_RDONLY | O_BINARY,0)) < 0)
  736.         goto report_error;
  737. #endif
  738. #ifdef NO_MMAP
  739.     if(!(p = (Char *)imalloc(statbuf.st_size)))
  740.     {
  741.         close(fd);
  742.         return(0);
  743.     }
  744. #ifdef VMS
  745.     q = p;
  746.     remain = statbuf.st_size;
  747.     while(remain > 0)
  748.     {
  749.         if((nbytes = read(fd,q,remain)) <= 0)
  750.             break;
  751.         q += nbytes;
  752.         remain -= nbytes;
  753.     }
  754.     statbuf.st_size -= remain;
  755. #else
  756.     if((l = read(fd,p,statbuf.st_size)) != statbuf.st_size)
  757.     {
  758.         slip_message("That file didn't read in correctly.");
  759.         wait_message();
  760.         statbuf.st_size = l;
  761.     }
  762. #endif
  763.     close(fd);
  764. #else
  765.     p = (Char *)mmap(0,statbuf.st_size,PROT_READ | PROT_WRITE,MAP_PRIVATE,fd,0);
  766.     close(fd);
  767.     if(p == (Char *)(-1))
  768.         return(0);
  769. #endif
  770.     for(m = (mmap_ptr)&base;m->next;m = m->next);
  771.     m->next = (mmap_ptr)imalloc(sizeof(mmap_node));
  772.     m = m->next;
  773.     m->next = NULL;
  774.     m->adr = p;
  775.     *bytes = m->len = statbuf.st_size;
  776.     return(p);
  777. }
  778.  
  779. /******************************************************************************\
  780. |Routine: unmap_file
  781. |Callby: include_file main
  782. |Purpose: Unmaps a file.
  783. |Arguments:
  784. |    adr is the base address of the mapped region.
  785. \******************************************************************************/
  786. void unmap_file(adr)
  787. Char *adr;
  788. {
  789.     mmap_ptr m,p;
  790.     
  791.     for(p = (mmap_ptr)&base,m = base;m;p = m,m = m->next)
  792.         if(m->adr == adr)
  793.         {
  794. #ifdef NO_MMAP
  795.             ifree(adr);
  796. #else
  797.             munmap(adr,m->len);
  798. #endif
  799.             p->next = m->next;
  800.             ifree(m);
  801.             return;
  802.         }
  803.     vtend();
  804.     printf("\nA call to unmap_file passed an unrecognized address.\n");
  805.     cleanup(0);
  806.     exit(0);
  807. }
  808.  
  809. /******************************************************************************\
  810. |Routine: checkbook
  811. |Callby: load_file
  812. |Purpose: Checks whether a file has a bookmark. Returns the position found in
  813. |         the bookmark file, or 0.
  814. |Arguments:
  815. |    editfile is the name of the file.
  816. |    bookmark is the returned bookmark file name, or null string.
  817. |    byteoffset is the byte offset within the record.
  818. \******************************************************************************/
  819. Int checkbook(editfile,bookmark,byteoffset)
  820. Char *editfile,*bookmark;
  821. Int *byteoffset;
  822. {
  823. #ifdef GNUDOS
  824.     bookmark[0] = '\0';
  825.     return(0);
  826. #else
  827.     FILE *fp;
  828.     Int initline;
  829.     
  830.     strcpy(bookmark,editfile);
  831.     strcat(bookmark,"-EDbookmark");
  832.     initline = 0;
  833.     if((fp = fopen(bookmark,"r")))
  834.     {
  835.         if(my_fscanf(fp,"%d,%d",&initline,byteoffset) == 2)
  836.         {
  837.             if(initline < 1)
  838.                 initline = 1;
  839.             fclose(fp);
  840.         }
  841.         else
  842.         {
  843.             fclose(fp);
  844.             bookmark[0] = '\0';
  845.         }
  846.     }
  847.     else
  848.         bookmark[0] = '\0';
  849.     return(initline);
  850. #endif
  851. }
  852.  
  853. /******************************************************************************\
  854. |Routine: read_stdin
  855. |Callby: load_file
  856. |Purpose: Reads an ASCII file from standard input, creating records.
  857. |Arguments:
  858. |    fname is the buffer that receives the file name.
  859. |    base is the base of the file's record queue.
  860. \******************************************************************************/
  861. Int read_stdin(fname,base)
  862. Char *fname;
  863. rec_ptr base;
  864. {
  865.     Char buffer[BUFFER_SIZE];
  866.     register rec_ptr new;
  867.     register Int i,nrecs;
  868.     
  869.     nrecs = 0;
  870.     strcpy(fname," Standard Input ");
  871.     new = NULL;
  872.     while(gets(buffer))
  873.     {
  874.         if((i = strlen(buffer)) == BUFFER_SIZE)
  875.             i--;
  876.         buffer[i++] = '\n';
  877.         nrecs++;
  878.         new = (rec_ptr)imalloc(sizeof(rec_node));    /* get new record */
  879.         insq(new,base->prev);
  880.         new->data = (Char *)imalloc(i);    /* get buffer for record */
  881.         if(--i > 0)    /* copy record data if present */
  882.             memcpy(new->data,buffer,i);
  883.         new->data[i] = 0;
  884.         new->length = i;
  885.         new->recflags = 1;
  886.     }
  887.     return(nrecs);
  888. }
  889.  
  890. /******************************************************************************\
  891. |Routine: read_stdin_binary
  892. |Callby: load_file
  893. |Purpose: Reads a binary file from standard input, creating records.
  894. |Arguments:
  895. |    fname is the buffer that receives the file name.
  896. |    base is the base of the file's record queue.
  897. \******************************************************************************/
  898. Int read_stdin_binary(fname,base)
  899. Char *fname;
  900. rec_ptr base;
  901. {
  902.     Char buffer[BUFFER_SIZE];
  903.     register Char *p,*stop;
  904.     register rec_ptr new;
  905.     register Int i,nrecs;
  906.  
  907.     nrecs = 0;
  908.     strcpy(fname," Standard Input ");
  909.     for(p = buffer,stop = buffer + BINARY_RECSIZE;(i = getchar()) != EOF;)
  910.     {
  911.         *p++ = i;
  912.         if(p == stop)
  913.         {
  914.             nrecs++;
  915.             new = (rec_ptr)imalloc(sizeof(rec_node));
  916.             insq(new,base->prev);
  917.             new->data = (Char *)imalloc(BINARY_RECSIZE);
  918.             memcpy(new->data,(p = buffer),BINARY_RECSIZE);
  919.             new->length = BINARY_RECSIZE;
  920.             new->recflags = 1;
  921.         }
  922.     }
  923.     if((i = p - buffer))
  924.     {
  925.         nrecs++;
  926.         new = (rec_ptr)imalloc(sizeof(rec_node));
  927.         insq(new,base->prev);
  928.         new->data = (Char *)imalloc(i);
  929.         memcpy(new->data,buffer,i);
  930.         new->length = i;
  931.         new->recflags = 1;
  932.     }
  933.     return(nrecs);
  934. }
  935.  
  936. /******************************************************************************\
  937. |Routine: read_in
  938. |Callby: load_file
  939. |Purpose: Reads an ASCII file, creating records.
  940. |Arguments:
  941. |    mapped is the mapped file pointer.
  942. |   nbytes is the size of the mapped region.
  943. |    base is the base of the file's record queue.
  944. \******************************************************************************/
  945. Int read_in(mapped,nbytes,base)
  946. Char *mapped;
  947. Int nbytes;
  948. rec_ptr base;
  949. {
  950.     rec_ptr new;
  951.     register Int nrecs,inprog;
  952.     register Char *p,*q,*stop;
  953.     
  954.     nrecs = 0;
  955.     new = NULL;
  956.     inprog = 0;
  957.     for(stop = mapped + nbytes,q = p = mapped;p != stop;p++)
  958.         if(*p == '\n')
  959.         {
  960.             nrecs++;
  961.             new = (rec_ptr)imalloc(sizeof(rec_node));    /* get new record */
  962.             insq(new,base->prev);
  963.             new->data = q;    /* use mapped address as record data */
  964.             if((new->length = p - q) > 0)
  965.                 if(new->data[new->length - 1] == '\r')    /* NULL-terminate the buffer (mapped data are MAP_PRIVATE) */
  966.                     new->length--;
  967.             new->data[new->length] = '\0';
  968.             new->recflags = 0;    /* don't free this buffer, it's mapped file data */
  969.             q = p + 1;
  970.             inprog = 0;
  971.         }
  972.         else
  973.             inprog = 1;
  974.     if(inprog)    /* the last record doesn't have newline termination, handle it specially */
  975.     {
  976. #ifdef GNUDOS
  977.         for(stop = q;stop != p;stop++)
  978.             if(*stop == 26)
  979.                 break;
  980.         if(stop != p)
  981.         {
  982.             *stop = '\0';
  983.             if(!strlen(q))
  984.                 return(nrecs);
  985.             p = stop;
  986.         }
  987. #endif
  988.         nrecs++;
  989.         new = (rec_ptr)imalloc(sizeof(rec_node));    /* get new record */
  990.         insq(new,base->prev);
  991.         new->length = p - q;
  992.         new->data = (Char *)imalloc(new->length + 1);    /* use mapped address as record data */
  993.         memcpy(new->data,q,new->length);    /* copy data to buffer */
  994.         new->data[new->length] = 0;    /* NULL-terminate the buffer (mapped data are MAP_PRIVATE) */
  995.         new->recflags = 1;    /* this buffer should be freed */
  996.     }
  997.     return(nrecs);
  998. }
  999.  
  1000. /******************************************************************************\
  1001. |Routine: read_in_binary
  1002. |Callby: load_file
  1003. |Purpose: Reads a file in binary mode, creating 32-byte records.
  1004. |Arguments:
  1005. |    mapped is the mapped file pointer.
  1006. |   nbytes is the size of the mapped region.
  1007. |    base is the base of the file's record queue.
  1008. \******************************************************************************/
  1009. Int read_in_binary(mapped,nbytes,base)
  1010. Char *mapped;
  1011. Int nbytes;
  1012. rec_ptr base;
  1013. {
  1014.     register Int i,nrecs;
  1015.     register Char *p,*stop;
  1016.     rec_ptr new;
  1017.     
  1018.     nrecs = 0;
  1019.     for(stop = mapped + nbytes - BINARY_RECSIZE,p = mapped;p <= stop;p += BINARY_RECSIZE)
  1020.     {
  1021.         nrecs++;
  1022.         new = (rec_ptr)imalloc(sizeof(rec_node));
  1023.         insq(new,base->prev);
  1024.         new->data = p;
  1025.         new->length = BINARY_RECSIZE;
  1026.         new->recflags = 0;
  1027.     }
  1028.     if((i = (mapped + nbytes) - p))
  1029.     {
  1030.         nrecs++;
  1031.         new = (rec_ptr)imalloc(sizeof(rec_node));
  1032.         insq(new,base->prev);
  1033.         new->data = p;
  1034.         new->length = i;
  1035.         new->recflags = 0;
  1036.     }
  1037.     return(nrecs);
  1038. }
  1039.  
  1040. /******************************************************************************\
  1041. |Routine: host_in_name
  1042. |Callby: load_file read_in_diredit
  1043. |Purpose: Returns >0 if /xxx.yyy.zzz: is present in file name. Return value is
  1044. |         the offset to the character after the colon.
  1045. |Arguments:
  1046. |    lbuf is the file name.
  1047. \******************************************************************************/
  1048. Int host_in_name(lbuf)
  1049. Char *lbuf;
  1050. {
  1051.     Char *p,c;
  1052.     
  1053. #ifdef NO_FTP
  1054.     return(0);
  1055. #else
  1056.     if(lbuf[0] == '/')
  1057.     {
  1058.         for(p = lbuf + 1;(c = *p);p++)
  1059.         {
  1060.             if(c == ':')
  1061.                 break;
  1062.             if(!isalpha(c) && !isdigit(c) && c != '+' && c != '.' && c != '-' && c != '_' && c != '@')
  1063.             {
  1064.                 c = '\0';
  1065.                 break;
  1066.             }
  1067.         }
  1068.         if(c)    /* it's an /xxx.yyy.zzz: filename */
  1069.             return(++p - lbuf);
  1070.     }
  1071.     return(0);
  1072. #endif
  1073. }
  1074.  
  1075. /******************************************************************************\
  1076. |Routine: read_in_diredit
  1077. |Callby: load_file
  1078. |Purpose: Creates a diredit buffer.
  1079. |Arguments:
  1080. |    fname is the buffer that receives the title string. If a VMS system, this is
  1081. |         in the form disk:[dir.dir...]. Returns 1 on success, -2 on ftp failure.
  1082. |    buf is the directory name.
  1083. |    base is the base of the file's record queue.
  1084. \******************************************************************************/
  1085. Int read_in_diredit(fname,buf,base)
  1086. Char *fname,*buf;
  1087. rec_ptr base;
  1088. {
  1089.     Char retbuf[512],lbuf[512],cwd[512],host[512],record[512],command[512],usr[64],fbuf[512],fbuf1[512],monthyear[512],msgbuf[128];
  1090.     rec_ptr new,tmp;
  1091.     struct stat statbuf;
  1092.     Int i,l,nrecs,ihour,ftpsystem,lasttime,thistime,ticker,mustrestore;
  1093.     Long context;
  1094.     Char *p,*q,c;
  1095. /* variables used for parsing remote listings */
  1096.     Char mode[64],group[64],owner[64],month[64],hour[64],*recptr;
  1097.     Int links,size,day,pred,year,minute,imonth;
  1098.     
  1099.     strcpy(lbuf,buf);
  1100. /* handle remote host directories */
  1101. #ifndef NO_FTP
  1102.     if((i = host_in_name(lbuf)))    /* this is true if /xxx.yyy.zzz: is in the file name */
  1103.     {
  1104.         p = extract_host(i,lbuf,host,usr);
  1105. /* get the directory listing from the remote host */
  1106.         if(!ftp_open(host,usr))
  1107.             return(-2);
  1108.         ftpsystem = ftp_system(buf);
  1109.         p = host_filename(i,lbuf,fname);
  1110.         if(ftpsystem == 'I' || ftpsystem == 'T')    /* VM systems emulate VMS systems, mostly */
  1111.         {
  1112.             if(strlen(p))
  1113.             {
  1114.                 p++;    /* advance past [ character */
  1115.                 if((q = strchr(p,']')))    /* find ] character */
  1116.                 {
  1117.                     if(!*(q + 1))    /* only a directory is specified, strip [, ] from VM dirname */
  1118.                         *q = '\0';
  1119.                     else
  1120.                         return(-1);    /* there is a file name present, fail */
  1121.                 }
  1122.                 sprintf(command,"CWD %s",p);
  1123.             }
  1124.             else
  1125.                 command[0] = '\0';
  1126.         }
  1127.         else
  1128.         {
  1129.             if(ftpsystem == 'M' || ftpsystem == 'O' || ftpsystem == 'W')
  1130.             {
  1131.                 if(strlen(p) > 1)
  1132.                 {
  1133.                     if(!(strlen(p) == 3 && *(p + 1) == ':' && *(p + 2) == '/'))
  1134.                         if(*(q = p + strlen(p) - 1) == '/')
  1135.                             *q = '\0';
  1136.                 }
  1137.                 strcpy(mode,"rwxrwxrwx");
  1138.             }
  1139.             sprintf(command,"CWD %s",p);
  1140.         }
  1141.         if(strlen(command))
  1142.             if(!ftp_command(command))    /* the -1 tells caller to try opening it as a file, rather than a directory */
  1143.                 if(!strstr(last_message(),"ataset"))
  1144.                     return(-1);
  1145.         if(!ftp_data("LIST"))
  1146.             return(-2);
  1147.         new = (rec_ptr)imalloc(sizeof(rec_node));
  1148.         insq(new,base->prev);
  1149. /* insert a record allowing user to move up */
  1150.         if(ftp_unixy(ftpsystem))
  1151.         {
  1152.             new->data = (Char *)imalloc(FILENAME_OFFSET + strlen("..") + 1);    /* get buffer for record */
  1153.             sprintf(new->data,"d        0                              ..");
  1154.         }
  1155.         else
  1156.         {
  1157.             new->data = (Char *)imalloc(FILENAME_OFFSET + strlen("[-]") + 1);    /* get buffer for record */
  1158.             sprintf(new->data,"d        0                              [-]");
  1159.         }
  1160.         new->length = strlen(new->data);
  1161.         new->recflags = 1;
  1162.         nrecs = 1;
  1163.         if(ftpsystem == 'U')
  1164.         {
  1165.             if(!ftp_record(record))    /* return 1 because ".." or "[-]" is always present */
  1166.                 return(1);
  1167.             if(!strstr(record,"otal"))
  1168.                 goto nototal;
  1169.         }
  1170.         lasttime = time(0);
  1171.         ticker = 0;
  1172. /* get directory listing */
  1173.         while(ftp_record(record))
  1174.         {
  1175.             if(!strlen(record))
  1176.                 continue;            
  1177. /* check for report of files listed */
  1178.             ticker = (ticker + 1) & 31;
  1179.             if(!ticker)
  1180.             {
  1181.                 thistime = time(0);
  1182.                 if(thistime - lasttime > 2)
  1183.                 {
  1184.                     if(ttychk() == 3)
  1185.                     {
  1186.                         ftp_abort();
  1187.                         break;
  1188.                     }
  1189.                     lasttime = thistime;
  1190.                     sprintf(msgbuf,"Total files so far: %d.",nrecs);
  1191.                     move(BOTROW,1);
  1192.                     ers_end();
  1193.                     reverse();
  1194.                     putz(msgbuf);
  1195.                     normal();
  1196.                     putout();
  1197.                     mustrestore = 1;
  1198.                 }
  1199.             }
  1200. nototal:
  1201. /* unix systems */
  1202. /*
  1203. dr-xr-xr-x   1 owner    group             0 Aug 13 11:13 cs
  1204. -r-xr-xr-x   1 owner    group          1420 Aug  3  8:53 README.TXT
  1205. */
  1206.             if(ftpsystem == 'U')
  1207.             {
  1208.                 memcpy(mode,record + 1,9);    /* get mode separately, since it may glom into link count */
  1209.                 mode[9] = '\0';
  1210.                 p = record + 10;
  1211.                 if(*p == '+')
  1212.                     p++;
  1213.                 if(my_sscanf(p,"%d %s %s %d %s %d %s %n",&links,group,owner,&size,month,&day,hour,&pred) != 7)
  1214.                     if(my_sscanf(p,"%d %s %d %s %d %s %n",&links,owner,&size,month,&day,hour,&pred) != 6)
  1215.                     {
  1216.                         strcpy(mode,"?????????");    /* no permission info */
  1217.                         fake_date(&size,&year,month,&day,&ihour,&minute);
  1218.                         strcpy(hour,"06:35");
  1219. /* maybe it looks like this?
  1220. GPC_PLB/              =  Picture Level Benchmark files
  1221. README              685  General info about this site
  1222. README.TeX3.141    3237  
  1223. TeX3.141.tar.Z  9664553  
  1224. a.e.d/                -  Archive of alt.education.disabled postings
  1225. anyone/               =  World writable directory for new software
  1226. bin/                  -  
  1227. describe-1.8.sgi.tar.Z
  1228.                  124985  Tools to provide descriptive ls, what you are seeing
  1229.  */
  1230.                         if(strlen(record) >= 23 && (record[22] == '-' || record[22] == '='))
  1231.                         {
  1232.                             size = 0;
  1233.                             for(p = record + 21;*p == ' ';p--);
  1234.                             if(*p == '/')
  1235.                             {
  1236.                                 *p = '\0';
  1237.                                 strcpy(fbuf,record);
  1238.                                 record[0] = 'd';    /* record[0] is reported to the first column of the diredit record */
  1239.                             }
  1240.                             else
  1241.                             {
  1242.                                 *++p = '\0';
  1243.                                 strcpy(fbuf,record);
  1244.                                 record[0] = '-';
  1245.                             }
  1246.                         }
  1247.                         else if((p = strchr(record,' ')))
  1248.                         {
  1249.                             if(my_sscanf(p,"%d",&size) != 1)
  1250.                                 size = 0;
  1251.                             *p = '\0';
  1252.                             strcpy(fbuf,record);
  1253.                             record[0] = '-';
  1254.                         }
  1255.                         else
  1256.                         {
  1257.                             strcpy(fbuf,record);
  1258.                             if(!ftp_record(record))
  1259.                                 break;
  1260.                             if(my_sscanf(record,"%d",&size) != 1)
  1261.                                 size = 0;
  1262.                             if(fbuf[strlen(fbuf) - 1] == '/')
  1263.                                 record[0] = 'd';
  1264.                             else
  1265.                                 record[0] = '-';
  1266.                         }
  1267.                         recptr = fbuf;
  1268.                     }
  1269.                 if(mode[0] != '?')    /* note that this will not happen if the weird format above obtains */
  1270.                     for(recptr = p + pred;*recptr == ' ';recptr++);    /* skip spaces after the hour, leaving recptr aimed at file name  */
  1271.             }
  1272. /* MSDOS system
  1273.  124436480           CDISK.TAR   Thu Jul 22 16:53:32 1993
  1274. <dir>                      SAV   Thu Jul 22 16:53:46 1993
  1275.  */
  1276.             else if(ftpsystem == 'M')
  1277.             {
  1278.                 if(!strncmp(record,"<dir>",(pred = strlen("<dir>"))))
  1279.                     size = 0;
  1280.                 else
  1281.                     if(my_sscanf(record,"%d%n",&size,&pred) != 1)
  1282.                         continue;
  1283.                 for(p = record + pred;isspace(*p);p++);
  1284.                 for(q = p + 1;!isspace(*q);q++);
  1285.                 *q = '\0';
  1286.                 strcpy(fbuf,p);
  1287.                 q += 7;    /* skip foward past day-of-week */
  1288.                 if(my_sscanf(q,"%s%d%d:%d:%d%d",month,&day,&ihour,&minute,&i,&year) != 6)
  1289.                     continue;
  1290.                 sprintf(hour,"%02d:%02d",ihour,minute);
  1291.                 recptr = fbuf;
  1292.                 record[0] = (record[0] == '<')? 'd' : '-';
  1293.             }
  1294. /* OS/2 system
  1295.                  0           DIR   07-24-93   13:55  DOS
  1296.               8440      A          09-08-92   20:35  OS2LDR.MSG
  1297. */
  1298.             else if(ftpsystem == 'O')
  1299.             {
  1300.                 if(my_sscanf(record,"%d",&size) != 1)
  1301.                     continue;
  1302.                 record[0] = (record[29] == 'D')? 'd' : '-';
  1303.                 if(my_sscanf(record + 35,"%d-%d-%d%s",&i,&day,&year,hour) != 4)
  1304.                     continue;
  1305.                 memcpy(month,months + (i - 1) * 3,3);
  1306.                 month[3] = '\0';
  1307.                 year += (year < 70)? 2000 : 1900;
  1308.                 strcpy(fbuf,record + 53);
  1309.                 recptr = fbuf;
  1310.             }
  1311. /* MTS system
  1312. r                 Jul 21  1991 ADDHELP.ZIP
  1313. */
  1314.             else if(ftpsystem == 'T')
  1315.             {
  1316.                 size = 0;
  1317.                 if(my_sscanf(record,"%s%s%d%s%s",fbuf,month,&day,hour,fbuf1) != 5)
  1318.                     if(my_sscanf(record,"%s%d%s%d%s%s",fbuf,&size,month,&day,hour,fbuf1) != 6)
  1319.                         continue;
  1320.                 strcpy(mode,"---------");    /* MTS reports as rw or whatever */
  1321.                 if(strchr(fbuf,'r'))
  1322.                     mode[0] = mode[3] = mode[6] = 'r';
  1323.                 if(strchr(fbuf,'w'))
  1324.                     mode[1] = mode[4] = mode[7] = 'w';
  1325.                 if(strchr(fbuf,'e') || strchr(fbuf,'x'))
  1326.                     mode[2] = mode[5] = mode[8] = 'x';
  1327.                 recptr = fbuf1;
  1328.             }
  1329. /* VM system */
  1330.             else if(ftpsystem == 'I')
  1331.             {
  1332. /*$READ-ME FIRST    V         71         27          1  4/28/93  3:22:47 PUBLIC*/
  1333.                 if(my_sscanf(record,"%s%s%s%d%d%d%d/%d/%d%d:%d",fbuf,fbuf1,monthyear,&i,&i,&size,&imonth,&day,&year,&ihour,&minute) == 11)
  1334.                 {
  1335.                     size *= 8;    /* it's going to be multiplied by 512 below. assume 4096-byte blocks */
  1336.                     strcpy(mode,"?????????");    /* VM doesn't report permission info */
  1337.                     memcpy(month,months + 3 * (imonth - 1),3);
  1338.                     month[3] = '\0';
  1339.                     year += (year < 70)? 2000 : 1900;
  1340.                     strcat(fbuf,".");
  1341.                     strcat(fbuf,fbuf1);
  1342.                     recptr = fbuf;
  1343.                 }
  1344. /*APR87                       FILE41 PS FB    133 11440*/
  1345.                 else if(my_sscanf(record,"%s%s%s%s%d%d",fbuf,fbuf1,fbuf1,fbuf1,&i,&i) == 6)
  1346.                 {
  1347.                     strcpy(mode,"?????????");    /* VM doesn't report permission info */
  1348.                     fake_date(&size,&year,month,&day,&ihour,&minute);
  1349.                     recptr = fbuf;
  1350.                 }
  1351.                 else
  1352.                 {
  1353.                     if((p = strchr(record,' ')))
  1354.                     {
  1355.                         *p = '\0';
  1356.                         sprintf(fbuf,"[%s]",record);
  1357.                         fake_date(&size,&year,month,&day,&ihour,&minute);
  1358.                         strcpy(mode,"?????????");
  1359.                         recptr = fbuf;
  1360.                     }
  1361.                     else
  1362.                         continue;
  1363.                 }
  1364.             }
  1365. /* WNT system */
  1366.             else if(ftpsystem == 'W')
  1367.             {
  1368. /*
  1369. 08-10-93  09:50AM                   96 GO.BAT
  1370. 05-06-93  10:53AM       <DIR>          OADDOS
  1371. */
  1372.                 if(my_sscanf(record,"%d-%d-%d%d:%s%s%s",&day,&imonth,&year,&ihour,fbuf,fbuf1,monthyear) == 7)
  1373.                 {
  1374.                     if(fbuf[2] == 'P')
  1375.                         ihour += 12;
  1376.                     fbuf[2] = '\0';
  1377.                     my_sscanf(fbuf,"%d",&minute);
  1378.                     sprintf(hour,"%02d:%02d",ihour,minute);
  1379.                     memcpy(month,months + (imonth - 1) * 3,3);
  1380.                     month[3] = '\0';
  1381.                     year += (year < 70)? 2000 : 1900;
  1382.                     if(!strcmp(fbuf1,"<DIR>"))
  1383.                     {
  1384.                         record[0] = 'd';
  1385.                         size = 0;
  1386.                     }
  1387.                     else
  1388.                     {
  1389.                         record[0] = '-';
  1390.                         my_sscanf(fbuf1,"%d",&size);
  1391.                     }
  1392.                     recptr = monthyear;
  1393.                 }
  1394. /*
  1395. dr-xr-xr-x   1 owner    group             0 Aug 13 11:13 cs
  1396. -r-xr-xr-x   1 owner    group          1420 Aug  3  8:53 README.TXT
  1397. */
  1398.                 else
  1399.                 {
  1400.                     memcpy(mode,record + 1,9);    /* get mode separately, since it may glom into link count */
  1401.                     mode[9] = '\0';
  1402.                     p = record + 10;
  1403.                     if(*p == '+')
  1404.                         p++;
  1405.                     if(my_sscanf(p,"%d %s %s %d %s %d %s %n",&links,group,owner,&size,month,&day,hour,&pred) != 7)
  1406.                         if(my_sscanf(p,"%d %s %d %s %d %s %n",&links,owner,&size,month,&day,hour,&pred) != 6)
  1407.                             continue;
  1408.                     for(recptr = p + pred;*recptr == ' ';recptr++);    /* skip spaces after the hour, leaving recptr aimed at file name  */
  1409.                 }
  1410.             }
  1411.             else if((p = strchr(record,';')))    /* VMS has ; only where filename appears */
  1412.             {
  1413. /*
  1414. 22AVG.FIL;1                     File ID:  (69,1,0)
  1415. Size:           2/3             Owner: [RHR]
  1416. Created:   27-DEC-1987 17:31    Revised:  24-MAY-1989 11:00
  1417. Expires:   <None specified>     Backup:   <None specified>
  1418. File organization:  Sequential
  1419. File attributes:    Allocation: 3, Extend: 0, Global buffer count: 0
  1420.                     No version limit
  1421. Record format:      Fixed length, maximum 512 bytes
  1422. Journaling enabled: None
  1423. File protection:    System:RWED,Owner:RWED,Group:RE,World:
  1424. Access Cntrl List:  None
  1425.  */
  1426.                 if(strstr(record,"File ID:"))    /* this server uses DIR/FULL listing, yawn */
  1427.                 {
  1428.                     while(!isspace(*++p));    /* trim blanks after file name */
  1429.                     *p = '\0';
  1430.                     fix_vms_dir(record,fbuf);    /* fix up .DIR;1 files */
  1431.                     if(!ftp_record(record))
  1432.                         break;
  1433.                     for(p = record;!isspace(*p);p++);    /* retrieve file size */
  1434.                     my_sscanf(p,"%d",&size);
  1435.                     if(!ftp_record(record))
  1436.                         break;
  1437.                     if(!(p = strstr(record,"Revised:")))    /* retrieve revision date */
  1438.                     {
  1439.                         fake_date(&size,&year,month,&day,&ihour,&minute);
  1440. bad_mode:
  1441.                         strcpy(mode,"?????????");
  1442.                     }
  1443.                     else
  1444.                     {
  1445.                         p += 8;
  1446.                         while(isspace(*p))
  1447.                             p++;
  1448.                         for(q = p;(c = *q);q++)
  1449.                             if(c == '-' || c == ':')
  1450.                                 *q = ' ';
  1451.                         my_sscanf(p,"%d %s %d %d %d",&day,month,&year,&ihour,&minute);
  1452.                         month[1] = tolower(month[1]);
  1453.                         month[2] = tolower(month[2]);
  1454.                         while(!strstr(record,"File protection:"))    /* read forward until protection info appears */
  1455.                             if(!(i = ftp_record(record)))
  1456.                                 break;
  1457.                         if(!i)    /* premature termination of listing */
  1458.                             break;
  1459.                         if(!(p = strstr(record,"Owner:")))    /* parse out the protection info */
  1460.                             goto bad_mode;
  1461.                         parse_vms_perms(p += strlen("Owner:"),mode);
  1462.                         if(!(p = strstr(record,"Group:")))
  1463.                             goto bad_mode;
  1464.                         parse_vms_perms(p += strlen("Group:"),mode + 3);
  1465.                         if(!(p = strstr(record,"World:")))
  1466.                             goto bad_mode;
  1467.                         parse_vms_perms(p += strlen("World:"),mode + 6);
  1468.                         mode[9] = '\0';
  1469.                     }
  1470.                 }
  1471. /* parse other VMS listing formats */
  1472.                 else
  1473.                 {
  1474.                     while(*p && !isspace(*p))    /* find end of record or whitespace */
  1475.                         p++;
  1476.                     if(!*p)    /* only the filename appears, it's either a two-liner, or a horrible system */
  1477.                     {
  1478.                         strcpy(fbuf,record);
  1479.                         if(!ftp_record(record))
  1480.                             break;
  1481.                         if(!isspace(record[0]))    /* it's one of those horrible systems that don't tell you anything about files */
  1482.                         {
  1483.                             fake_date(&size,&year,month,&day,&ihour,&minute);    /* use fake date info */
  1484.                             strcpy(mode,"?????????");    /* use confused permission info */
  1485.                             fix_vms_dir(fbuf,fbuf);    /* handle .DIR;1 files */
  1486.                             new = (rec_ptr)imalloc(sizeof(rec_node));    /* load the previously-read file name */
  1487.                             insq(new,base->prev);
  1488.                             new->data = (Char *)imalloc((l = strlen(fbuf)) + 1 + FILENAME_OFFSET);    /* get buffer for record */
  1489.                             sprintf(new->data,"%c %s %s  %4d %02d-%02d %02d:%02d  %s",((fbuf[0] == '[')? 'd' : ' '),size_string(size),mode,year,i,day,ihour,minute,fbuf);
  1490.                             new->data[l + FILENAME_OFFSET] = 0;
  1491.                             new->length = l + FILENAME_OFFSET;
  1492.                             new->recflags = 1;
  1493.                             nrecs++;
  1494.                             while(strchr(record,';'))    /* get the rest of the file names */
  1495.                             {
  1496. /* check for report of files listed */
  1497.                                 ticker = (ticker + 1) & 31;
  1498.                                 if(!ticker)
  1499.                                 {
  1500.                                     thistime = time(0);
  1501.                                     if(thistime - lasttime > 2)
  1502.                                     {
  1503.                                         if(ttychk() == 3)
  1504.                                         {
  1505.                                             ftp_abort();
  1506.                                             break;
  1507.                                         }
  1508.                                         lasttime = thistime;
  1509.                                         sprintf(msgbuf,"Total files so far: %d.",nrecs);
  1510.                                         move(BOTROW,1);
  1511.                                         ers_end();
  1512.                                         reverse();
  1513.                                         putz(msgbuf);
  1514.                                         normal();
  1515.                                         putout();
  1516.                                         mustrestore = 1;
  1517.                                     }
  1518.                                 }
  1519.                                 fix_vms_dir(record,record);
  1520.                                 new = (rec_ptr)imalloc(sizeof(rec_node));    /* get new record */
  1521.                                 insq(new,base->prev);
  1522.                                 new->data = (Char *)imalloc((l = strlen(record)) + 1 + FILENAME_OFFSET);    /* get buffer for record */
  1523.                                 sprintf(new->data,"%c %s %s  %4d %02d-%02d %02d:%02d  %s",((record[0] == '[')? 'd' : ' '),size_string(size),mode,year,i,day,ihour,minute,record);
  1524.                                 new->data[l + FILENAME_OFFSET] = 0;
  1525.                                 new->length = l + FILENAME_OFFSET;
  1526.                                 new->recflags = 1;
  1527.                                 nrecs++;
  1528.                                 if(!ftp_record(record))
  1529.                                     break;
  1530.                             }
  1531.                             if(mustrestore && NWINDOWS)
  1532.                                 paint(BOTROW,BOTROW,FIRSTCOL);
  1533.                             return(nrecs);
  1534.                         }
  1535.                         p = record;
  1536.                     }
  1537.                     else    /* it was a two-liner */
  1538.                     {
  1539.                         *p++ = '\0';
  1540.                         strcpy(fbuf,record);
  1541.                     }
  1542.                     fix_vms_dir(fbuf,fbuf);
  1543. /* at this point, we have the filename or [.dirname] in fbuf, and p points at whitespace hopefully preceeding one of the following:
  1544.  
  1545. DIGLIB.DIR;1        %RMS-E-PRV, insufficient privilege or file protection violation
  1546. LOGIN.COM;2          no privilege for attempted operation
  1547. DINK.BCK;1                441   1-FEB-1993 10:02 [ANONYMOUS] (RWED,RWED,RE,RE)
  1548. VMS-DECWINDOWS.DIR;1
  1549.                             1   1-SEP-1990 17:07 [ASD,BRAND] (RWE,RWE,RE,RE)
  1550. USER$DISK:[ANONYMOUS]ETHER.TXT;2                  12/12         4-AUG-1988 11:40
  1551. 00-INDEX.ALL;4        5-NOV-1992 14:43:39    18092/36     (RWED,RWED,R,R)
  1552. 00._THIS_SITE_NO_LONGER_EXISTS;1
  1553.                      30-JUN-1992 09:04:23        0/0      (RWED,RWED,,)
  1554. CAESAR.DIR;1              1  13-JUN-1992 13:18:42.55  (RWED,RWED,RE,RE)
  1555. archie.rfa;2                    MAR 22 16:04 1993    24064 (,RWE,RE,RE)
  1556. VISIT$DISK:[ANONYMOUS]DDN.TAR;1
  1557. FTPSTUFF.DIR;1  1/3     29-APR-1991    [INTERNET,ANONYMOUS]   (RWE,RWE,RE,RE)
  1558.  
  1559. */
  1560. /* check for privilege problems */
  1561.                     if(strchr(p,'%') || strstr(p,"no privilege"))
  1562.                     {
  1563.                         fake_date(&size,&year,month,&day,&ihour,&minute);
  1564.                         strcpy(mode,"?????????");
  1565.                     }
  1566. /* try the known forms one at a time */
  1567.                     else
  1568.                     {
  1569.                         strcpy(mode,"?????????");    /* default is meaningless permission info */
  1570. /*DINK.BCK;1                441   1-FEB-1993 10:02 [ANONYMOUS] (RWED,RWED,RE,RE)*/
  1571.                         if(my_sscanf(p,"%d%d-%s%d:%d",&size,&day,monthyear,&ihour,&minute) == 5)
  1572.                             parse_monthyear(monthyear,&size,&year,month,&day,&ihour,&minute,mode,p);
  1573. /*USER$DISK:[ANONYMOUS]ETHER.TXT;2                  12/12         4-AUG-1988 11:40*/
  1574.                         else if(my_sscanf(p,"%d/%d%d-%s%d:%d",&size,&i,&day,monthyear,&ihour,&minute) == 6)
  1575.                             parse_monthyear(monthyear,&size,&year,month,&day,&ihour,&minute,mode,p);
  1576. /*00-INDEX.ALL;4        5-NOV-1992 14:43:39    18092/36     (RWED,RWED,R,R)*/
  1577.                         else if(my_sscanf(p,"%d-%s%d:%d:%d%d/%d",&day,monthyear,&ihour,&minute,&i,&i,&size) == 7)
  1578.                             parse_monthyear(monthyear,&size,&year,month,&day,&ihour,&minute,mode,p);
  1579. /*CAESAR.DIR;1              1  13-JUN-1992 13:18:42.55  (RWED,RWED,RE,RE)*/
  1580.                         else if(my_sscanf(p,"%d%d-%s%d:%d",&size,&day,monthyear,&ihour,&minute) == 5)
  1581.                             parse_monthyear(monthyear,&size,&year,month,&day,&ihour,&minute,mode,p);
  1582. /*FTPSTUFF.DIR;1  1/3     29-APR-1991    [INTERNET,ANONYMOUS]   (RWE,RWE,RE,RE)*/
  1583.                         else if(my_sscanf(p,"%d/%d%d-%s",&size,&i,&day,monthyear) == 4)
  1584.                         {
  1585.                             ihour = minute = 0;
  1586.                             parse_monthyear(monthyear,&size,&year,month,&day,&ihour,&minute,mode,p);
  1587.                         }
  1588. /*archie.rfa;2                    MAR 22 16:04 1993    24064 (,RWE,RE,RE)*/
  1589.                         else if(my_sscanf(p,"%s%d%d:%d%d%d",month,&day,&ihour,&minute,&year,&size) != 6)
  1590.                             fake_date(&size,&year,month,&day,&ihour,&minute);
  1591.                     }
  1592.                     month[1] = tolower(month[1]);
  1593.                     month[2] = tolower(month[2]);
  1594.                 }
  1595.                 if((p = strchr(fbuf,']')) && !strstr(fbuf,"[."))
  1596.                     recptr = ++p;
  1597.                 else
  1598.                     recptr = fbuf;
  1599.             }
  1600.             else    /* ignore extraneous (non-filename) records */
  1601.                 continue;
  1602. /* add to the buffer */
  1603.             new = (rec_ptr)imalloc(sizeof(rec_node));    /* get new record */
  1604.             insq(new,base->prev);
  1605.             new->data = (Char *)imalloc(FILENAME_OFFSET + (l = strlen(recptr)) + 1);    /* get buffer for record */
  1606.             if(ftp_unixy(ftpsystem))
  1607.                 sprintf(new->data,"%c %s %s  %s  %s",(record[0] == '-')? ' ' : record[0],size_string(size),mode,ftp_date(month,day,hour),recptr);
  1608.             else if(ftpsystem == 'T')
  1609.             {
  1610.                 i = ((strstr(months,month) - months) / 3) + 1;
  1611.                 sprintf(new->data,"  %s %s  %s  %s",size_string(size),mode,ftp_date(month,day,hour),recptr);
  1612.             }
  1613.             else
  1614.             {
  1615.                 i = ((strstr(months,month) - months) / 3) + 1;
  1616.                 size <<= 9;    /* VMS reports number of 512-byte blocks */
  1617.                 sprintf(new->data,"%c %s %s  %4d %02d-%02d %02d:%02d  %s",((fbuf[0] == '[')? 'd' : ' '),size_string(size),mode,year,i,day,ihour,minute,recptr);
  1618.             }
  1619.             new->data[FILENAME_OFFSET + l] = 0;
  1620.             new->length = FILENAME_OFFSET + l;
  1621.             new->recflags = 1;
  1622.             nrecs++;
  1623.         }    /* end of while(ftp_record(record)) */
  1624. /* remove any . or .. entries that are not the first record */
  1625.         for(new = base->next->next;new != base;new = new->next)
  1626.             if(!strcmp(new->data + FILENAME_OFFSET,".") || !strcmp(new->data + FILENAME_OFFSET,".."))
  1627.             {
  1628.                 tmp = new->prev;
  1629.                 remq(new);
  1630.                 ifree(new->data);
  1631.                 ifree(new);
  1632.                 nrecs--;
  1633.                 new = tmp;
  1634.             }
  1635.         if(mustrestore && NWINDOWS)
  1636.             paint(BOTROW,BOTROW,FIRSTCOL);
  1637.         return(nrecs);
  1638.     }
  1639. #endif    /* not NO_FTP */
  1640. #ifdef GNUDOS
  1641.     while((p = strchr(lbuf,'\\')))
  1642.         *p = '/';
  1643. #endif
  1644. /* convert the name to absolute pathname */
  1645. #ifndef VMS
  1646.     if(lbuf[0] != '/')
  1647.     {
  1648. #ifdef GNUDOS
  1649.         if(lbuf[1] != ':')
  1650.         {
  1651. #endif
  1652. #ifdef NeXT
  1653.         getwd(cwd);
  1654. #else
  1655.         getcwd(cwd,sizeof(cwd));
  1656. #endif
  1657. #ifdef GNUDOS
  1658.         while((p = strchr(cwd,'\\')))
  1659.             *p = '/';
  1660. #endif
  1661.         strcat(cwd,"/");
  1662.         strcat(cwd,lbuf);
  1663.         strcpy(lbuf,cwd);
  1664. #ifdef GNUDOS
  1665.         }
  1666. #endif
  1667.     }
  1668.     if(lbuf[strlen(lbuf) - 1] != '/')    /* add / to end */
  1669.         strcat(lbuf,"/");
  1670.     while((p = strstr(lbuf,"//")))        /* eliminate all // */
  1671.         for(q = p + 1;(*p++ = *q++););
  1672.     while((p = strstr(lbuf,"/./")))        /* eliminate all /./ */
  1673.         for(q = p + 2;(*p++ = *q++););
  1674.     while((p = strstr(lbuf,"/../")))    /* convert /../ to abs pathname */
  1675.     {
  1676.         q = p + 3;
  1677.         if(!(p == lbuf || (p == lbuf + 2 && lbuf[1] == ':')))
  1678.             while(*--p != '/');            /* back up unless at start of string */
  1679.         while((*p++ = *q++));
  1680.     }
  1681. #endif    /* not VMS */
  1682. /* set the title */
  1683.     strcpy(fname,lbuf);
  1684.     nrecs = 0;
  1685. /* load the files */
  1686. #ifdef VMS
  1687.     strcat(lbuf,"*.*;*");
  1688. #else
  1689.     strcat(lbuf,"*");
  1690. #endif
  1691.     if((context = find_files(lbuf)))
  1692.     {
  1693. #ifdef VMS
  1694.         new = (rec_ptr)imalloc(sizeof(rec_node));
  1695.         insq(new,base->prev);
  1696.         new->data = (Char *)imalloc(FILENAME_OFFSET + 3 + 1);    /* get buffer for record */
  1697.         sprintf(new->data,"d        0                              [-]");
  1698.         new->length = strlen(new->data);
  1699.         new->recflags = 1;
  1700. #endif
  1701.         while(next_file(context,retbuf))
  1702.         {
  1703.             if(!nrecs++)
  1704.             {
  1705.                 p = retbuf;
  1706.                 l = filename(p) - p;
  1707.             }
  1708.             if(stat(retbuf,&statbuf))
  1709.             {
  1710.                 statbuf.st_size = 0;
  1711.                 statbuf.st_mode = 0;
  1712.                 statbuf.st_mtime = 0;
  1713.             }
  1714.             new = (rec_ptr)imalloc(sizeof(rec_node));    /* get new record */
  1715.             insq(new,base->prev);
  1716.             new->data = (Char *)imalloc((i = strlen(retbuf) - l) + FILENAME_OFFSET + 1);    /* get buffer for record */
  1717. #ifdef VMS
  1718.             if(S_ISDIR(statbuf.st_mode))
  1719.             {
  1720.                 strcpy(cwd,filename(retbuf));
  1721.                 *(strstr(cwd,".DIR")) = '\0';
  1722.                 sprintf(new->data,"d %s %s  %s  [.%s]",size_string(statbuf.st_size),mode_string(statbuf.st_mode),proper_date(statbuf.st_mtime),cwd);
  1723.                 i = strlen(cwd) + 3;
  1724.             }
  1725.             else
  1726. #endif
  1727.             sprintf(new->data,"%c %s %s  %s  %s",S_ISDIR(statbuf.st_mode)? 'd' : ' ',
  1728.                 size_string(statbuf.st_size),mode_string(statbuf.st_mode),proper_date(statbuf.st_mtime),retbuf + l);
  1729.             new->data[FILENAME_OFFSET + i] = 0;
  1730.             new->length = FILENAME_OFFSET + i;
  1731.             new->recflags = 1;
  1732.         }
  1733.         find_files_end(context);
  1734.     }
  1735.     return(nrecs);
  1736. }
  1737.  
  1738. #ifndef NO_FTP
  1739. /******************************************************************************\
  1740. |Routine: read_in_ftp
  1741. |Callby: load_file
  1742. |Purpose: Downloads a file in FTP mode.
  1743. |Arguments:
  1744. |    fname is the buffer that receives the title string. If a VMS system, this is
  1745. |         in the form disk:[dir.dir...]. Returns total records, or -2 if ftp
  1746. |         fails, or -1 if CWD fails.
  1747. |    buf is the file name.
  1748. |    base is the base of the file's record queue.
  1749. |   binary is a flag that the file is to be read in binary mode.
  1750. \******************************************************************************/
  1751. Int read_in_ftp(fname,buf,base,binary)
  1752. Char *fname,*buf;
  1753. rec_ptr base;
  1754. Char binary;
  1755. {
  1756.     rec_ptr new;
  1757.     Int i,l,m,nrecs,ftpsystem,mustrestore;
  1758.     Int lasttime,thistime,ticker,totalread,lasttotal,throughput,filesize,percent;
  1759.     Char *p,*q,host[512],dir[512],fil[512],lbuf[512],*record,msgbuf[128];
  1760.     Char command[512],usr[64];
  1761.     
  1762.     ftpsystem = ftp_system(buf);    /* this works because we tried read_in_diredit first */
  1763.     strcpy(lbuf,buf);
  1764.     i = host_in_name(lbuf);
  1765.     p = extract_host(i,lbuf,host,usr);
  1766.     strcpy(dir,p);
  1767.     if(ftp_unixy(ftpsystem))
  1768.     {
  1769.         if(dir[(l = strlen(dir) - 1)] == '/')
  1770.             dir[l] = '\0';
  1771.         if(!(q = strrchr(dir,'/')))
  1772.         {
  1773.             strcpy(fil,dir);
  1774.             strcpy(dir,".");    /* No directory present, use default (cws) */
  1775.         }
  1776.         else
  1777.         {
  1778.             *q++ = '\0';
  1779.             strcpy(fil,q);
  1780.             if(!strlen(dir))
  1781.                 strcpy(dir,"/");
  1782.         }
  1783.     }
  1784.     else
  1785.     {
  1786.         if((q = strchr(dir,']')))
  1787.         {
  1788.             strcpy(fil,++q);
  1789.             *q = '\0';
  1790.         }
  1791.         else if((q = strchr(dir,':')))
  1792.         {
  1793.             strcpy(fil,++q);
  1794.             *q = '\0';
  1795.         }
  1796.         else
  1797.         {
  1798.             strcpy(fil,dir);
  1799.             dir[0] = '\0';
  1800.         }
  1801.     }
  1802. /* open the connection to the remote host */
  1803.     if(!ftp_open(host,usr))
  1804.         return(-2);
  1805.     p = host_filename(i,lbuf,fname);
  1806.     if(*(q = fname + strlen(fname) - 1) == '/')    /* trim trailing / */
  1807.         *q = '\0';
  1808.     if(ftpsystem == 'I')
  1809.     {
  1810.         if(strlen(++p))
  1811.         {
  1812.             if((q = strchr(p,']')))
  1813.                 *q = '\0';
  1814.             sprintf(command,"CWD %s",p);
  1815.             if(!ftp_command(command))
  1816.             {
  1817.                 sprintf(command,"Unable to move to the directory '%s'.",p);
  1818.                 ftp_error(command);
  1819.                 return(-2);
  1820.             }
  1821.         }
  1822.     }
  1823.     else
  1824.     {
  1825.         if(ftpsystem == 'T')
  1826.         {
  1827.             if(dir[0] == '[')
  1828.             {
  1829.                 strcpy(buf,dir + 1);
  1830.                 if((q = strchr(buf,']')))
  1831.                     *q = '\0';
  1832.                 strcpy(dir,buf);
  1833.             }
  1834.         }
  1835.         sprintf(command,"CWD %s",dir);
  1836.         ftp_command(command);    /* we ignore errors here because some servers don't let you even CWD to where you are */
  1837.     }
  1838.     mustrestore = 0;    /* flag that we have issued progress messages and must set them right */
  1839.     totalread = 0;    /* count of bytes read from remote host */
  1840.     lasttotal = 0;    /* count at last report (for calculating throughput) */
  1841.     if(binary)    /* a binary-mode get */
  1842.     {
  1843.         if(!ftp_command("TYPE i"))
  1844.             return(-2);
  1845.         sprintf(command,"RETR %s",fil);
  1846.         if(!ftp_data(command))
  1847.         {
  1848.             if(!ftp_command("TYPE a"))
  1849.                 return(-2);
  1850.             return(-2);
  1851.         }
  1852.         nrecs = 0;
  1853.         ftpbin = 1;
  1854.         lasttime = time(0);
  1855.         ticker = 0;
  1856.         filesize = 0;
  1857.         if(CURWINDOW >= 0)
  1858.             if(CURREC && CURREC != WINDOW[CURWINDOW].base)
  1859.                 if(my_sscanf(CURREC->data + 1,"%d",&filesize) != 1)
  1860.                     filesize = 0;
  1861.         record = (Char *)imalloc(512);    /* the 512 here must match what ftp_binary expects */
  1862.         while((l = ftp_binary(record)))
  1863.         {
  1864.             p = record;
  1865.             while(l > 0)
  1866.             {
  1867.                 m = (l > 32)? 32 : l;    /* limit records to 32 bytes */
  1868.                 new = (rec_ptr)imalloc(sizeof(rec_node));    /* get new record */
  1869.                 insq(new,base->prev);
  1870.                 new->data = (Char *)imalloc(m + 1);    /* get buffer for record */
  1871.                 memcpy(new->data,p,m);
  1872.                 new->data[m] = '\0';
  1873.                 new->length = m;
  1874.                 new->recflags = 1;
  1875.                 nrecs++;
  1876.                 totalread += m;
  1877.                 if(filesize)    /* report progress */
  1878.                 {
  1879.                     ticker = (ticker + 1) & 31;
  1880.                     if(!ticker)
  1881.                     {
  1882.                         thistime = time(0);
  1883.                         if(thistime - lasttime > 2)
  1884.                         {
  1885.                             if(ttychk() == 3)
  1886.                             {
  1887.                                 ftp_abort();
  1888.                                 goto abort_binary;
  1889.                             }
  1890.                             throughput = (totalread - lasttotal) / 2;
  1891.                             lasttotal = totalread;
  1892.                             lasttime = thistime;
  1893.                             percent = (int)((100.0 * (float)totalread) / ((float)filesize));
  1894.                             sprintf(msgbuf,"Retrieving (binary mode) %s - %d%% (throughput = %d)",fil,percent,throughput);
  1895.                             move(BOTROW,1);
  1896.                             ers_end();
  1897.                             reverse();
  1898.                             putz(msgbuf);
  1899.                             normal();
  1900.                             putout();
  1901.                             mustrestore = 1;
  1902.                         }
  1903.                     }
  1904.                 }
  1905.                 l -= 32;
  1906.                 p += 32;
  1907.             }
  1908. abort_binary:
  1909.             ;
  1910.         }
  1911.         ifree(record);
  1912.         if(!ftp_command("TYPE a"))
  1913.             return(-2);
  1914.     }
  1915.     else    /* an ascii mode get */
  1916.     {
  1917.         lasttime = time(0);
  1918.         ticker = 0;
  1919.         filesize = 0;
  1920.         if(CURWINDOW >= 0)
  1921.             if(CURREC && CURREC != WINDOW[CURWINDOW].base)
  1922.                 if(my_sscanf(CURREC->data + 1,"%d",&filesize) != 1)
  1923.                     filesize = 0;
  1924.         sprintf(command,"RETR %s",fil);
  1925.         if(!ftp_data(command))
  1926.             return(-2);
  1927.         nrecs = 0;
  1928.         record = (Char *)imalloc(32768);    /* this limits the size of FTP-acquired ascii records to 32768 bytes */
  1929.         while(ftp_ascii(record,32768))
  1930.         {
  1931.             new = (rec_ptr)imalloc(sizeof(rec_node));    /* get new record */
  1932.             insq(new,base->prev);
  1933.             if((l = strlen(record)))
  1934.                 if(record[l - 1] == '\r')
  1935.                     l--;
  1936.             new->data = (Char *)imalloc(l + 1);    /* get buffer for record */
  1937.             strcpy(new->data,record);
  1938.             new->data[l] = '\0';
  1939.             new->length = l;
  1940.             new->recflags = 1;
  1941.             nrecs++;
  1942.             totalread += l;
  1943.             if(filesize)
  1944.             {
  1945.                 ticker = (ticker + 1) & 31;
  1946.                 if(!ticker)
  1947.                 {
  1948.                     thistime = time(0);
  1949.                     if(thistime - lasttime > 2)
  1950.                     {
  1951.                         if(ttychk() == 3)
  1952.                         {
  1953.                             ftp_abort();
  1954.                             break;
  1955.                         }
  1956.                         throughput = (totalread - lasttotal) / 2;
  1957.                         lasttotal = totalread;
  1958.                         lasttime = thistime;
  1959.                         percent = (100 * totalread) / filesize;
  1960.                         sprintf(msgbuf,"Retrieving (ascii mode) %s - %d%% (throughput = %d)",fil,percent,throughput);
  1961.                         move(BOTROW,1);
  1962.                         ers_end();
  1963.                         reverse();
  1964.                         putz(msgbuf);
  1965.                         normal();
  1966.                         putout();
  1967.                         mustrestore = 1;
  1968.                     }
  1969.                 }
  1970.             }
  1971.         }
  1972.         ifree(record);
  1973.     }
  1974.     if(mustrestore)
  1975.         paint(BOTROW,BOTROW,FIRSTCOL);
  1976.     return(nrecs);
  1977. }
  1978. #endif
  1979.  
  1980. /******************************************************************************\
  1981. |Routine: load_file
  1982. |Callby: edit include_file main wincom
  1983. |Purpose: Reads an entire file into a record queue. Returns the number of records,
  1984. |         or -1 if the file doesn't exist, or -2 if it was an ftp file and an
  1985. |         error occurred (and has already been reported).
  1986. |Arguments:
  1987. |    fname is the name of the file to read in.
  1988. |    base is the record queue into which the file goes.
  1989. |    bookmark is the name of the bookmark file, if one exists.
  1990. |    bookpos is the number of lines to move down in the buffer.
  1991. |    bookbyt is the byte offset within the marked record.
  1992. |    diredit is a returned flag that this is a directory file.
  1993. |    binary is a flag that the file should be loaded in binary mode.
  1994. |    filebuf is a returned pointer to the mapped file, or NULL.
  1995. \******************************************************************************/
  1996. Int load_file(fname,base,bookmark,bookpos,bookbyt,diredit,binary,filebuf)
  1997. Char *fname;
  1998. rec_ptr base;
  1999. Char *bookmark;
  2000. Int *bookpos,*bookbyt;
  2001. Char *diredit;
  2002. Char binary;
  2003. Char **filebuf;
  2004. {
  2005.     register Char *p,*q;
  2006.     Int i,l,nbytes,bfound;
  2007.     Long context;
  2008.     Char ext[512];
  2009.     Char buffer[512];
  2010.     Char buf[512],retbuf[512],lbuf[512];
  2011.     Char *mapped;
  2012.     struct stat statbuf;
  2013. #ifdef VMS
  2014.     Int m;
  2015.     struct desc_str
  2016.     {
  2017.         unsigned short length,class;
  2018.         Char *string;
  2019.     } desc;
  2020. #endif
  2021.  
  2022.     if(forcebinary)
  2023.     {
  2024.         forcebinary = 0;
  2025.         binary = 1;
  2026.     }
  2027.     bookmark[0] = '\0';
  2028.     maperror = 0;    /* no map_file error has occurred */
  2029.     *filebuf = NULL;    /* default is no file buffer */
  2030.     strcpy(buf,fname);
  2031.     strip_quotes(buf);
  2032.     envir_subs(buf);
  2033. /* check for -b or -h in file name */
  2034.     if(!binary)    /* if they specified binary, we don't need or want to check. if they didn't, and -b or -h is present, it overrides. */
  2035.         if((bfound = parse_option(buf,'b')) || parse_option(buf,'h'))
  2036.         {
  2037.             binary = 1;
  2038.             strcpy(fname,buf);    /* parse_option has remove the -b */
  2039.         }
  2040.     if(!strlen(fname))    /* this happens if they just say -b or -h without a file */
  2041.         if(bfound)
  2042.             strcpy(fname,"-b");    /* this lets them actually edit a file called -b */
  2043.         else
  2044.             strcpy(fname,"-h");
  2045.     if(strchr(buf,'*') || strchr(buf,'?') || strstr(buf,"..."))    /* find first match if wildcards are present */
  2046.         if((context = find_files(buf)))
  2047.         {
  2048.             if(next_file(context,retbuf))
  2049.                 strcpy(buf,retbuf);
  2050.             find_files_end(context);
  2051.         }
  2052.     base->next = base->prev = base;
  2053.     strcpy(lbuf,fname);
  2054. #ifdef VMS
  2055.     m = strlen(lbuf) - 1;
  2056.     for(i = 0;i <= m;i++)    /* convert <> to [] */
  2057.         if(lbuf[i] == '<')
  2058.             lbuf[i] = '[';
  2059.         else if(lbuf[i] == '>')
  2060.             lbuf[i] = ']';
  2061.     if(lbuf[m] == ']')    /* is a directory file */
  2062.     {
  2063.         *diredit = 1;
  2064.         if((p = strstr(buf,"[]")))
  2065.         {
  2066.             desc.class = 0x010e;
  2067.             desc.length = sizeof(retbuf);
  2068.             desc.string = retbuf;
  2069.             SYS$SETDDIR(NULL,&i,&desc);
  2070.             retbuf[i] = '\0';
  2071.             strcpy(p,retbuf);
  2072.         }
  2073.         return(read_in_diredit(fname,buf,base));
  2074.     }
  2075. #endif
  2076. #ifndef NO_FTP
  2077.     if((i = host_in_name(fname)))
  2078.     {
  2079.         if(!fileonly)
  2080.         {
  2081.             if((i = read_in_diredit(fname,buf,base)) > 0)
  2082.             {
  2083.                 *diredit = 1;
  2084.                 return(i);
  2085.             }
  2086.             else if(i == -2)    /* we fall through here if it returns -1, which means CWD failed */
  2087.                 return(-2);
  2088.         }
  2089.         fileonly = 0;    /* ftp_fileonly is a one-shot deal */
  2090. /* open as directory failed, try opening as file */
  2091.         *diredit = 0;
  2092.         if(buf[(l = strlen(buf) - 1)] == '/')
  2093.             buf[l] = '\0';
  2094.         return(read_in_ftp(fname,buf,base,binary));
  2095.     }
  2096. #endif
  2097.     fileonly = 0;    /* just to be sure */
  2098.     if(!stat(fname,&statbuf))
  2099.         if(S_ISDIR(statbuf.st_mode))
  2100.         {
  2101.             *diredit = 1;
  2102.             return(read_in_diredit(fname,buf,base));
  2103.         }
  2104.     *diredit = 0;
  2105.     if(!strncmp(buf,"./",2))
  2106.         for(p = buf,q = buf + 2;(*p++ = *q++););
  2107.     if(binary)
  2108.     {
  2109. #ifndef VMS
  2110.         if(!strcmp(buf,"-"))
  2111.             return(read_stdin_binary(fname,base));
  2112. #endif
  2113.         if((*filebuf = mapped = map_file(buf,&nbytes)))
  2114.         {
  2115.             if((i = checkbook(buf,bookmark,bookbyt)))
  2116.                 *bookpos = i;
  2117.             strcpy(fname,buf);
  2118.             return(read_in_binary(mapped,nbytes,base));
  2119.         }
  2120.         else if(maperror)
  2121.             return(-2);
  2122.     }
  2123.     else
  2124.     {
  2125. #ifndef VMS
  2126.         if(!strcmp(buf,"-"))
  2127.             return(read_stdin(fname,base));
  2128. #endif
  2129.         if((*filebuf = mapped = map_file(buf,&nbytes)))
  2130.         {
  2131.             if((i = checkbook(buf,bookmark,bookbyt)))
  2132.                 *bookpos = i;
  2133.             strcpy(fname,buf);
  2134.             return(read_in(mapped,nbytes,base));
  2135.         }
  2136.         else if(maperror)
  2137.             return(-2);
  2138.     }
  2139. /* file as given not found, try extensions if none present */
  2140.     if(!(p = (Char *)extension(buf)))
  2141.     {
  2142.         p = buf + strlen(buf);    /* skip ahead in the file name, preparing to append extensions */
  2143.         *p++ = '.';
  2144.         strcpy(buffer,DEFAULT_EXT);    /* prepare to parse extensions from string */
  2145.         while(get_token(buffer,ext))
  2146.         {
  2147.             strcpy(p,ext);
  2148.             if((*filebuf = mapped = map_file(buf,&nbytes)))
  2149.             {
  2150.                 if((i = checkbook(buf,bookmark,bookbyt)))
  2151.                     *bookpos = i;
  2152.                 strcpy(fname,buf);
  2153.                 if(binary)
  2154.                     return(read_in_binary(mapped,nbytes,base));
  2155.                 else
  2156.                     return(read_in(mapped,nbytes,base));
  2157.             }
  2158.             else if(maperror)
  2159.                 return(-2);
  2160.         }
  2161.         *--p = '\0';    /* remove the extension before returning to caller */
  2162.     }
  2163.     return(-1);
  2164. }
  2165.  
  2166.